﻿using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Reflection;

namespace XTrace
{
	public partial class XTraceSource
	{
		[Conditional("TRACE")]
		public void Critical(string eventId)
		{
			TraceCore(XTraceLevel.Critical, eventId);
		}
		
		[Conditional("TRACE")]
		public void Critical(bool condition, string eventId)
		{
			if (condition)
			{
				TraceCore(XTraceLevel.Critical, eventId);
			}
		}
		
		[Conditional("TRACE")]
		public void Critical(string eventId, object additionalInformation)
		{
			TraceCore(XTraceLevel.Critical, eventId, additionalInformation);
		}
		
		[Conditional("TRACE")]
		public void Critical(bool condition, string eventId, object additionalInformation)
		{
			if (condition)
			{
				TraceCore(XTraceLevel.Critical, eventId, additionalInformation);
			}
		}
		
		[Conditional("TRACE")]
		public void Critical(string eventId, string additionalInformation, params object[] args)
		{
			TraceCore(XTraceLevel.Critical, eventId, additionalInformation, args);
		}
		
		[Conditional("TRACE")]
		public void Critical(bool condition, string eventId, string additionalInformation, params object[] args)
		{
			if (condition)
			{
				TraceCore(XTraceLevel.Critical, eventId, additionalInformation, args);
			}
		}
		
		[Conditional("TRACE")]
		public void Error(string eventId)
		{
			TraceCore(XTraceLevel.Error, eventId);
		}
		
		[Conditional("TRACE")]
		public void Error(bool condition, string eventId)
		{
			if (condition)
			{
				TraceCore(XTraceLevel.Error, eventId);
			}
		}
		
		[Conditional("TRACE")]
		public void Error(string eventId, object additionalInformation)
		{
			TraceCore(XTraceLevel.Error, eventId, additionalInformation);
		}
		
		[Conditional("TRACE")]
		public void Error(bool condition, string eventId, object additionalInformation)
		{
			if (condition)
			{
				TraceCore(XTraceLevel.Error, eventId, additionalInformation);
			}
		}
		
		[Conditional("TRACE")]
		public void Error(string eventId, string additionalInformation, params object[] args)
		{
			TraceCore(XTraceLevel.Error, eventId, additionalInformation, args);
		}
		
		[Conditional("TRACE")]
		public void Error(bool condition, string eventId, string additionalInformation, params object[] args)
		{
			if (condition)
			{
				TraceCore(XTraceLevel.Error, eventId, additionalInformation, args);
			}
		}
		
		[Conditional("TRACE")]
		public void Warning(string eventId)
		{
			TraceCore(XTraceLevel.Warning, eventId);
		}
		
		[Conditional("TRACE")]
		public void Warning(bool condition, string eventId)
		{
			if (condition)
			{
				TraceCore(XTraceLevel.Warning, eventId);
			}
		}
		
		[Conditional("TRACE")]
		public void Warning(string eventId, object additionalInformation)
		{
			TraceCore(XTraceLevel.Warning, eventId, additionalInformation);
		}
		
		[Conditional("TRACE")]
		public void Warning(bool condition, string eventId, object additionalInformation)
		{
			if (condition)
			{
				TraceCore(XTraceLevel.Warning, eventId, additionalInformation);
			}
		}
		
		[Conditional("TRACE")]
		public void Warning(string eventId, string additionalInformation, params object[] args)
		{
			TraceCore(XTraceLevel.Warning, eventId, additionalInformation, args);
		}
		
		[Conditional("TRACE")]
		public void Warning(bool condition, string eventId, string additionalInformation, params object[] args)
		{
			if (condition)
			{
				TraceCore(XTraceLevel.Warning, eventId, additionalInformation, args);
			}
		}
		
		[Conditional("TRACE")]
		public void Important(string eventId)
		{
			TraceCore(XTraceLevel.Important, eventId);
		}
		
		[Conditional("TRACE")]
		public void Important(bool condition, string eventId)
		{
			if (condition)
			{
				TraceCore(XTraceLevel.Important, eventId);
			}
		}
		
		[Conditional("TRACE")]
		public void Important(string eventId, object additionalInformation)
		{
			TraceCore(XTraceLevel.Important, eventId, additionalInformation);
		}
		
		[Conditional("TRACE")]
		public void Important(bool condition, string eventId, object additionalInformation)
		{
			if (condition)
			{
				TraceCore(XTraceLevel.Important, eventId, additionalInformation);
			}
		}
		
		[Conditional("TRACE")]
		public void Important(string eventId, string additionalInformation, params object[] args)
		{
			TraceCore(XTraceLevel.Important, eventId, additionalInformation, args);
		}
		
		[Conditional("TRACE")]
		public void Important(bool condition, string eventId, string additionalInformation, params object[] args)
		{
			if (condition)
			{
				TraceCore(XTraceLevel.Important, eventId, additionalInformation, args);
			}
		}
		
		[Conditional("TRACE")]
		public void Information()
		{
			TraceCore(XTraceLevel.Information);
		}
		
		[Conditional("TRACE")]
		public void Information(bool condition)
		{
			if (condition)
			{
				TraceCore(XTraceLevel.Information);
			}
		}
		
		[Conditional("TRACE")]
		public void Information(string eventId)
		{
			TraceCore(XTraceLevel.Information, eventId);
		}
		
		[Conditional("TRACE")]
		public void Information(bool condition, string eventId)
		{
			if (condition)
			{
				TraceCore(XTraceLevel.Information, eventId);
			}
		}
		
		[Conditional("TRACE")]
		public void Information(string eventId, object additionalInformation)
		{
			TraceCore(XTraceLevel.Information, eventId, additionalInformation);
		}
		
		[Conditional("TRACE")]
		public void Information(bool condition, string eventId, object additionalInformation)
		{
			if (condition)
			{
				TraceCore(XTraceLevel.Information, eventId, additionalInformation);
			}
		}
		
		[Conditional("TRACE")]
		public void Information(string eventId, string additionalInformation, params object[] args)
		{
			TraceCore(XTraceLevel.Information, eventId, additionalInformation, args);
		}
		
		[Conditional("TRACE")]
		public void Information(bool condition, string eventId, string additionalInformation, params object[] args)
		{
			if (condition)
			{
				TraceCore(XTraceLevel.Information, eventId, additionalInformation, args);
			}
		}
		
		[Conditional("TRACE")]
		public void Verbose()
		{
			TraceCore(XTraceLevel.Verbose);
		}
		
		[Conditional("TRACE")]
		public void Verbose(bool condition)
		{
			if (condition)
			{
				TraceCore(XTraceLevel.Verbose);
			}
		}
		
		[Conditional("TRACE")]
		public void Verbose(string eventId)
		{
			TraceCore(XTraceLevel.Verbose, eventId);
		}
		
		[Conditional("TRACE")]
		public void Verbose(bool condition, string eventId)
		{
			if (condition)
			{
				TraceCore(XTraceLevel.Verbose, eventId);
			}
		}
		
		[Conditional("TRACE")]
		public void Verbose(string eventId, object additionalInformation)
		{
			TraceCore(XTraceLevel.Verbose, eventId, additionalInformation);
		}
		
		[Conditional("TRACE")]
		public void Verbose(bool condition, string eventId, object additionalInformation)
		{
			if (condition)
			{
				TraceCore(XTraceLevel.Verbose, eventId, additionalInformation);
			}
		}
		
		[Conditional("TRACE")]
		public void Verbose(string eventId, string additionalInformation, params object[] args)
		{
			TraceCore(XTraceLevel.Verbose, eventId, additionalInformation, args);
		}
		
		[Conditional("TRACE")]
		public void Verbose(bool condition, string eventId, string additionalInformation, params object[] args)
		{
			if (condition)
			{
				TraceCore(XTraceLevel.Verbose, eventId, additionalInformation, args);
			}
		}
		

		readonly string _name;
		readonly Assembly _asm;

		public XTraceSource(string name)
		{
			_name = name;
			_asm = Assembly.GetCallingAssembly();
		}


		#region Trace XTraceLevel

		[Conditional("TRACE")]
		[EditorBrowsable(EditorBrowsableState.Advanced)]
		public void Trace(XTraceLevel importance, string eventId)
		{
			Trace(importance, eventId, null);
		}

		[Conditional("TRACE")]
		[EditorBrowsable(EditorBrowsableState.Advanced)]
		public void Trace(XTraceLevel importance, string eventId, object someinfo)
		{
			Trace(importance, eventId, someinfo == null ? null : someinfo.ToString(), null);
		}

		[Conditional("TRACE")]
		[EditorBrowsable(EditorBrowsableState.Advanced)]
		public void Trace(XTraceLevel importance, string eventId, string someinfo, params object[] args)
		{
			PrepareInfo(args, ref someinfo);
			TraceCore(importance, eventId, someinfo);
		}

		#endregion

		[Conditional("TRACE")]
		public void Exception(Exception ex, string eventId, string message, params object[] args)
		{
			TraceCore(XTraceLevel.Exception, eventId, message + Environment.NewLine + ex, args);
		}

		[Conditional("TRACE")]
		public void Exception(Exception ex, string eventId)
		{
			TraceCore(XTraceLevel.Exception, eventId, ex.ToString());
		}

		[Conditional("TRACE")]
		public void Exception(Exception ex)
		{
			TraceCore(XTraceLevel.Exception, XTraceSource.GetEventFromStack(ex), ex.ToString());
		}

		void TraceCore(XTraceLevel importance)
		{
			TraceCore(importance, null);
		}

		void TraceCore(XTraceLevel importance, string eventId)
		{
			TraceCore(importance, eventId, null);
		}

		void TraceCore(XTraceLevel importance, string eventId, object additionalInfo)
		{
			TraceCore(importance, eventId, additionalInfo == null ? null : additionalInfo.ToString());
		}

		void TraceCore(XTraceLevel importance, string eventId, string additionalInfo, params object[] args)
		{
			PrepareInfo(args, ref additionalInfo);
			var traceEvent = new XTraceEvent(_name, importance,  eventId, additionalInfo, _asm);
			Notify(traceEvent);
		}

		#region Both for XTrace and XTraceSource

		static void NotifyAllStatic(XTraceEvent traceEvent)
		{
			foreach (var listener in XTraceListener.Listeners)
			{
				listener.Event(traceEvent);
			}
		}

		static void PrepareInfo(object[] args, ref string format)
		{
			if (format != null && args != null && args.Length > 0)
			{
				format = string.Format(format, args);
			}
		}

		#endregion

		#region LEGACY COMPATIBILITY

		[Conditional("TRACE")]
		[Obsolete("Use Critical, Exception, Error, Warning, Information, Verbose")]
		[EditorBrowsable(EditorBrowsableState.Never)]
		public void WriteLine(string message, params object[] args)
		{
			PrepareInfo(args, ref message);
			TraceCore(XTraceLevel.Information, "LEGACY WriteLine", message);
		}

		[Conditional("TRACE")]
		[Obsolete("Use Critical, Exception, Error, Warning, Information, Verbose")]
		[EditorBrowsable(EditorBrowsableState.Never)]
		public void WriteLineIf(bool condition, string message, params object[] args)
		{
			if (condition)
			{
				PrepareInfo(args, ref message);
				TraceCore(XTraceLevel.Information, "LEGACY WriteLine", message);
			}
		}

		#endregion
	}
}